package routers

import (
	"fmt"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/mcuadros/go-version"
	"reflect"
	"seawolf-admin-go/utility/response"
	"sort"
	"strconv"
	"strings"
)

type VersionStrategy uint8

const (
	// DefaultStrategy 如果找不到传入的版本，使用默认版本
	DefaultStrategy VersionStrategy = iota
	// DemoteStrategy 如果找不到传入的版本，降级使用最近的版本
	DemoteStrategy
)

// 版本号对比 version1 > version2 返回 1，version1 < version2 返回 -1，version1 == version2 返回 0
func compareVersion(version1 string, version2 string) int {
	var res int
	ver1Strs := strings.Split(version1, ".")
	ver2Strs := strings.Split(version2, ".")
	ver1Len := len(ver1Strs)
	ver2Len := len(ver2Strs)
	verLen := ver1Len
	if len(ver1Strs) < len(ver2Strs) {
		verLen = ver2Len
	}
	for i := 0; i < verLen; i++ {
		var ver1Int, ver2Int int
		if i < ver1Len {
			ver1Int, _ = strconv.Atoi(ver1Strs[i])
		}
		if i < ver2Len {
			ver2Int, _ = strconv.Atoi(ver2Strs[i])
		}
		if ver1Int < ver2Int {
			res = -1
			break
		}
		if ver1Int > ver2Int {
			res = 1
			break
		}
	}
	return res
}

// 获取控制器映射里面的全部 keys 并做倒序返回
func getControllerMapAllKeys(m map[string]interface{}) []string {
	j := 0
	keys := make([]string, len(m))
	for k := range m {
		keys[j] = k
		j++
	}
	sort.Slice(keys, func(i, j int) bool {
		//return keys[i] > keys[j]
		// 倒序
		return compareVersion(keys[i], keys[j]) > 0
	})
	return keys
}

// 取出最近的版本，并且小于当前版本
func getDemoteStrategyVersion(mapControllers map[string]interface{}, v string) string {
	versionNames := getControllerMapAllKeys(mapControllers)
	fmt.Println("versionNames ", versionNames)
	// 取出最近的版本，并且小于当前版本
	var tmpVersion string
	for _, vname := range versionNames {
		// 取到第一个小于等于当前版本的版本号
		if version.CompareSimple(vname, v) < 1 {
			tmpVersion = vname
			break
		}
	}
	fmt.Println("tmpVersion ", tmpVersion)
	//version.NewConstrainGroupFromString(">=1.0.0")
	return tmpVersion
}

func getBindFn(r *ghttp.Request, mapControllers map[string]interface{}, defaultVersion string, versionStrategy VersionStrategy) interface{} {
	v := r.Header.Get("version")
	var cFno interface{}
	if len(mapControllers) == 1 {
		// 只有一个版本，直接返回
		for k, i := range mapControllers {
			// 写入版本号
			r.Header.Set("version", k)
			cFno = i
		}
		return cFno
	}
	// 如果未传入版本号，使用默认版本
	if v == "" {
		v = defaultVersion
	}
	if fno, ok := mapControllers[v]; ok {
		cFno = fno
	} else {
		// 使用默认版本策略
		switch versionStrategy {
		case DefaultStrategy:
			// 使用默认版本
			cFno, ok = mapControllers[defaultVersion]
			if !ok {
				panic("default version " + defaultVersion + " not found")
			}
			r.Header.Set("version", defaultVersion)
			break
		case DemoteStrategy:
			// 降级策略
			// 按策略取出版本号
			tmpVersion := getDemoteStrategyVersion(mapControllers, v)

			cFno, ok = mapControllers[tmpVersion]
			if !ok {
				panic("version " + tmpVersion + " not found")
			}
			r.Header.Set("version", tmpVersion)
			break
		}
	}

	return cFno
}

func MethodCall(r *ghttp.Request, mapControllers map[string]interface{}, defaultVersion string) {
	MethodCallWithVersionStrategy(r, mapControllers, defaultVersion, DefaultStrategy)
}

func MethodCallWithVersionStrategy(r *ghttp.Request, mapControllers map[string]interface{}, defaultVersion string, versionStrategy VersionStrategy) {
	cFno := getBindFn(r, mapControllers, defaultVersion, versionStrategy)
	var inputObject reflect.Value
	var requestError error
	fn := reflect.ValueOf(cFno)
	inputValues := []reflect.Value{
		reflect.ValueOf(r),
	}
	if fn.Type().NumIn() == 2 {
		if fn.Type().In(1).Kind() == reflect.Ptr {
			inputObject = reflect.New(fn.Type().In(1).Elem())
			requestError = r.Parse(inputObject.Interface())
		} else {
			inputObject = reflect.New(fn.Type().In(1).Elem()).Elem()
			requestError = r.Parse(inputObject.Addr().Interface())
		}

		inputValues = append(inputValues, inputObject)
	}
	if requestError != nil {
		r.Response.ClearBuffer()
		r.SetError(requestError)
		return
	}

	results := fn.Call(inputValues)
	switch len(results) {
	case 1:
		if !results[0].IsNil() {
			if err, ok := results[0].Interface().(error); ok {
				requestError = err
			}
			// 适配返回类型为 *response.JsonResponse
			if res, ok := results[0].Interface().(*response.JsonResponse); ok {
				r.Response.ClearBuffer()
				r.Response.WriteJsonExit(res)
			}
		}

	case 2:
		if !results[1].IsNil() {
			if err, ok := results[1].Interface().(error); ok {
				requestError = err
			}
		} else {
			// 如果response 有输出，直接返回
			if r.Response.BufferLength() > 0 {
				return
			}
			// 无错误
			response.JsonExit(r, 0, "Success", results[0].Interface())
		}
	}

	if requestError != nil {
		r.Response.ClearBuffer()
		r.SetError(requestError)
		return
	}
}
